import React, {Component} from 'react';

export default class Welcome extends Component {
    constructor(props) {
        super(props)
        this.state = {
            currentValue: 0
        }
        this.fnQueue = []
    }

    // 对外暴露的接口，接受需要增加的数字
    add = (num) => {
        // 如果上次的累加还没结束 先加入队列
        if (this.isAdding) {
            this.fnQueue.push(this._excuteAdd.bind(this, num))
        } else {
            this._excuteAdd(num, true)
        }

    }

    _excuteAdd = (num, isImmediately) => {
        // 如果是执行队列里的方法 就把队列里的第一项移除
        if (!isImmediately) {
            this.fnQueue.pop()
        }
        this.isAdding = true
        const cache = this.state.currentValue
        const ANI_SECONDS = 1000
        // 每秒执行的次数 60帧率
        const EXCUTETIMES_PER_SECOND = 60
        // 执行频率/毫秒
        const RATE = ANI_SECONDS / EXCUTETIMES_PER_SECOND
        // 执行的次数 = 数字小于60的话就执行对应数字的次数，或者执行60次
        const addTime = Math.min(Math.floor(num), EXCUTETIMES_PER_SECOND)
        // 每次增加的数字 = 增加的总数 / 执行的次数 向下取整
        let eachAddNum = Math.ceil(num / addTime)
        // 记录执行完成的次数
        let doneNum = 0
        // 最终加出的结果
        const final = cache + num

        for (let i = 0; i < addTime; i++) {
            setTimeout(() => {
                this.setState({
                    currentValue: Math.min(this.state.currentValue + eachAddNum, final)
                })
                doneNum++
                // 异步调用链结束
                if (doneNum === addTime) {
                    // 校正结果
                    this.setState({
                        currentValue: final
                    })
                    if (!this.fnQueue.length) {
                        this.isAdding = false
                        return
                    }
                    // 执行队列里下条任务
                    const nextTask = this.fnQueue[0]
                    nextTask && nextTask()
                }
                // 增加数字的动画执行分别在 0 16ms 32ms ... 1s ，保证在1s内执行完成
            }, RATE * i)
        }
    }

    render() {
        return (
            <span {...this.props} ref={ref => this.numberDom = ref}>{this.state.currentValue}</span>
        )
    }
}
